package com.kgcx.schedule.service;

import com.kgcx.common.client.organization.AirportClient;
import com.kgcx.common.client.organization.StationClient;
import com.kgcx.common.client.organization.pojo.Airport;
import com.kgcx.common.client.organization.pojo.Driver;
import com.kgcx.common.client.organization.pojo.Station;
import com.kgcx.common.constant.Cons;
import com.kgcx.common.utils.CollectionUtils;
import com.kgcx.core.utils.HelpUtil;
import com.kgcx.core.utils.LngLatUtil;
import com.kgcx.schedule.domain.ScheduleRecordDomain;
import com.kgcx.schedule.domain.ScheduleReserveCfgDetailDomain;
import com.kgcx.schedule.model.OptionallyNow;
import com.kgcx.schedule.model.ScheduleException;
import com.kgcx.schedule.model.ScheduleRound;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * 立即用车
 *
 * @author 袁进勇
 */
@Service
public class ScheduleImmediatelyCommonOrderService extends ScheduleOrderNowService {
    private static final Logger LOG = LoggerFactory.getLogger(ScheduleImmediatelyCommonOrderService.class);
    @Autowired
    private AirportClient airportClient;
    @Autowired
    private StationClient stationClient;
    private OptionallyNow setting = null;

    @Override
    protected void checkRecord(ScheduleRecordDomain record, ScheduleReserveCfgDetailDomain cfgDetail)
            throws ScheduleException {
        driverList = getDriverList(record);
        //checkReserveQuantity(record, cfgDetail, driverList.size());
    }

    @Override
    protected Driver chooseDriver(ScheduleRecordDomain record, Map<Integer, List<Driver>> driverMap) {

        LOG.info(String.format("订单[%s]，调度车辆/司机。", record.getOrder_no()));
        Long cityId = record.getCity_id();
        OptionallyNow setting = getScheduleSetting(cityId);

        String planOrigLat = record.getPlan_orig_lat();
        String planOrigLng = record.getPlan_orig_lng();
        Driver driver;
        if (isInScope(cityId, planOrigLat, planOrigLng)) {//上车地点在机场或者高铁站围栏内
            LOG.info(String.format("订单[%s]，上车地点在机场围栏内。", record.getOrder_no()));
            // 1、有入栈车辆时，按入栈排队顺序调度
            driver = chooseStateInDriver(record, driverMap);
            if (driver != null) {
                LOG.info(String.format("订单[%s]，找到符合调度规则的入栈车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                        driver.getAutoId(), driver.getKid()));
                return driver;
            }

            // 2、有入栈中车辆时，按入栈中状态变更顺序调度
            driver = chooseStatePreInDriver(record, driverMap);
            if (driver != null) {
                LOG.info(String.format("订单[%s]，找到符合调度规则的入栈中车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                        driver.getAutoId(), driver.getKid()));
                return driver;
            }

            // 3、有待命车辆时，按待命排队顺序调度
            if (Cons.$true(setting.getIs_standby())) {
                driver = chooseStateStayDriver(record, driverMap);
                if (driver != null) {
                    LOG.info(String.format("订单[%s]，找到符合调度规则的待命车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                            driver.getAutoId(), driver.getKid()));
                    return driver;
                }
            } else {
                LOG.info(String.format("订单[%s]，立即接机/站的调度参数“是否给待命车辆派车”开关未开启。", record.getOrder_no()));
            }

            driver = chooseStateOnDriver(record, driverMap);
            // 4、场外在线车辆派单
            if (Cons.$true(setting.getIs_online())) {
                if (driver != null) {
                    LOG.info(String.format("订单[%s]，找到符合调度规则的场外在线车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                            driver.getAutoId(), driver.getKid()));
                    return driver;
                }
            } else {
                LOG.info(String.format("订单[%s]，立即接机/站的调度参数“是否给场外车辆派车”开关未开启。", record.getOrder_no()));
            }
        } else {
            LOG.info(String.format("订单[%s]，上车地点在机场围栏外。", record.getOrder_no()));
            driver = chooseStateOnDriver(record, driverMap);
            // 4、场外在线车辆派单
            if (Cons.$true(setting.getIs_online())) {
                if (driver != null) {
                    LOG.info(String.format("订单[%s]，找到符合调度规则的场外在线车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                            driver.getAutoId(), driver.getKid()));
                    return driver;
                }
            } else {
                LOG.info(String.format("订单[%s]，立即接机/站的调度参数“是否给场外车辆派车”开关未开启。", record.getOrder_no()));
            }

            // 3、有待命车辆时，按待命排队顺序调度
            if (Cons.$true(setting.getIs_standby())) {
                driver = chooseStateStayDriverWithDistance(record, driverMap);
                if (driver != null) {
                    LOG.info(String.format("订单[%s]，找到符合调度规则的待命车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                            driver.getAutoId(), driver.getKid()));
                    return driver;
                }
            } else {
                LOG.info(String.format("订单[%s]，立即接机/站的调度参数“是否给待命车辆派车”开关未开启。", record.getOrder_no()));
            }

            // 2、有入栈中车辆时，按入栈中状态变更顺序调度
            driver = chooseStatePreInDriverWithDistance(record, driverMap);
            if (driver != null) {
                LOG.info(String.format("订单[%s]，找到符合调度规则的入栈中车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                        driver.getAutoId(), driver.getKid()));
                return driver;
            }


            // 1、有入栈车辆时，按入栈排队顺序调度
            driver = chooseStateInDriverWithDistance(record, driverMap);
            if (driver != null) {
                LOG.info(String.format("订单[%s]，找到符合调度规则的入栈车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                        driver.getAutoId(), driver.getKid()));
                return driver;
            }
        }

        return null;
    }

    @Override
    protected ScheduleRound getScheduleRound(ScheduleRecordDomain record) {
        OptionallyNow setting = getScheduleSetting(record.getCity_id());
        if (Cons.$true(setting.getIs_online())) {
            List<ScheduleRound> rounds = setting.getRounds();
            if (!HelpUtil.isEmpty(rounds) && rounds.size() > record.getSchedule_count()) {
                return rounds.get(record.getSchedule_count());
            }
        }
        return null;
    }

    @Override
    protected void scheduleSuccessful(ScheduleRecordDomain record, Driver driver) {
        // 短信通知下单人
        OptionallyNow setting = getScheduleSetting(record.getCity_id());
        String placingUserPhone = record.getPlacing_user_phone();
        if (Cons.$true(setting.getIs_send_msg())) { // 短信发送开关打开
            sendSuccessfulMSG(placingUserPhone, setting.getMsg_id(), record);
        }

        // 给别人叫车时，检查是否短信通知乘车人
        String passengerPhone = record.getPassenger_phone();
        if (Cons.$true(record.getIs_msg_passenger())
                && (!HelpUtil.isEmpty(passengerPhone) && !passengerPhone.equals(placingUserPhone))) {
            sendSuccessfulMSG(passengerPhone, setting.getMsg_id(), record);
        }
    }

    private OptionallyNow getScheduleSetting(Long cityId) {
        return scheduleSettingsService.getSetting(cityId, OptionallyNow.class);
    }


    @Override
    protected void scheduleFailed(ScheduleRecordDomain record, Driver driver) {
        // 移入历史表
        scheduleRecordService.archiveScheduleRecord(record);
    }

    /**
     * 位置是否在围栏内
     *
     * @return
     */
    private boolean isInScope(Long cityId, String lat, String lng) {
        List<Airport> airportList = airportClient.getAirportList(cityId);
        if (CollectionUtils.isNotEmpty(airportList)) {
            for (Airport airport : airportList) {
                Double distance = LngLatUtil.getDistance(Double.valueOf(lat), Double.valueOf(lng), Double.valueOf(airport.getLat()), Double.valueOf(airport.getLng()));
                if (distance <= airport.getRange()) {
                    return true;
                }
            }
        }

        List<Station> stationList = stationClient.getStationList(cityId);
        if (CollectionUtils.isNotEmpty(stationList)) {
            for (Station station : stationList) {
                Double distance = LngLatUtil.getDistance(Double.valueOf(lat), Double.valueOf(lng), Double.valueOf(station.getLat()), Double.valueOf(station.getLng()));
                if (distance <= station.getRange()) {
                    return true;
                }
            }
        }
        return false;
    }

    private Driver chooseStateInDriverWithDistance(ScheduleRecordDomain record, Map<Integer, List<Driver>> driverMap) {
        List<Driver> driverList = driverMap.get(Cons.DRIVER_STATE_IN);
        if (HelpUtil.isEmpty(driverList)) {
            LOG.info(String.format("订单[%s]，入栈车辆/司机列表为空！", record.getOrder_no()));
            return null;
        }

        sortDriverListByLastUpdateStateTime(driverList);

        return chooseDriverByDistance(record, driverList);
    }

    protected Driver chooseStatePreInDriverWithDistance(ScheduleRecordDomain record, Map<Integer, List<Driver>> driverMap) {
        List<Driver> driverList = driverMap.get(Cons.DRIVER_STATE_PREIN);
        if (HelpUtil.isEmpty(driverList)) {
            LOG.info(String.format("订单[%s]，入栈中车辆/司机列表为空！", record.getOrder_no()));
            return null;
        }

        sortDriverListByLastUpdateStateTime(driverList);

        return chooseDriverByDistance(record, driverList);
    }

    protected Driver chooseStateStayDriverWithDistance(ScheduleRecordDomain record, Map<Integer, List<Driver>> driverMap) {
        List<Driver> driverList = driverMap.get(Cons.DRIVER_STATE_STAY);
        if (HelpUtil.isEmpty(driverList)) {
            LOG.info(String.format("订单[%s]，待命车辆/司机列表为空！", record.getOrder_no()));
            return null;
        }

        sortDriverListByLastUpdateStateTime(driverList);

        return chooseDriverByDistance(record, driverList);
    }

}
